from binn_list import BinnList
from binn_map import BinnMap
from binn_obj import BinnObj

def encode_dict(pyobj):
    keys = pyobj.keys()
    typ = type(list(keys)[0]) 
    for key in keys:
        if type(key) != typ:
            raise TypeError('inconsitent type') 
    binnc = None
    t = ''
    if typ == str:
        binnc = BinnObj()
        t = 'o'
    elif typ == int:
        binnc = BinnMap()
        t = 'm'
    else:
        raise TypeError('')
    for key, item in pyobj.items():
        if isinstance(item, float):
            binnc.set_double(key, item)
        elif isinstance(item, (int, bool)):
            binnc.set_int64(key, item)
        elif isinstance(item, str):
            binnl.set_str(key, item)
        elif isinstance(item, dict):
            typ, child = encode_dict(item)
            if typ == 'm':
                binnc.set_map(key, child)
            elif typ == 'o':
                binnc.set_obj(key, child)
            else:
                raise ValueError('')
        elif isinstance(item, (list, tuple, set)):
            child = encode_list(item)
            binnc.set_list(key, child)
        else:
            raise TypeError('')
    return t, binnc

def encode_list(pyobj):
    assert isinstance(pyobj, (list, tuple, set))
    binnl = BinnList()
    for item in pyobj:
        if isinstance(item, float):
            binnl.add_double(item)
        elif isinstance(item, (int, bool)):
            binnl.add_int64(item)
        elif isinstance(item, str):
            binnl.add_str(item)
        elif isinstance(item, dict):
            typ, child = encode_dict(item)
            if typ == 'm':
                binnl.add_map(child)
            elif typ == 'o':
                binnl.add_obj(child)
            else:
                raise ValueError('')
        elif isinstance(item, (list, tuple, set)):
            child = encode_list(item)
            binnl.add_list(child)
        else:
            raise TypeError('')
    return binnl
def encode(pyobj):
    if isinstance(pyobj, dict):
        t, binnc =  encode_dict(pyobj)
        return binnc
    elif isinstance(pyobj, (list, tuple, set)):
        return encode_list(pyobj)
